/*
	Worker.cpp

	Contains the functionality of the SnowstormX worker thread objects

	Author: Aidan Goddard 8/8/14
*/

#include<Windows.h>
#include<strsafe.h>
#include"Worker.h"
#include"Error.h"
#include"Dispatch.h"

////////////////////////////////////////////////////
// static data

Snowstorm::Worker **Snowstorm::Worker::workers = NULL;
int Snowstorm::Worker::worker_count = 0;

////////////////////////////////////////////////////
// thread entry point

static DWORD WINAPI ThreadEntryPoint(LPVOID lpparam)
{
	// get the thread object
	Snowstorm::Worker *w = static_cast<Snowstorm::Worker*>(lpparam);

	// call the instance main
	w->Main();

	// finished
	return 0;
}


////////////////////////////////////////////////////
// static functions
void Snowstorm::Worker::CreateWorkers(int count)
{
	if(count > 0)
	{
		// create an array of worker objects
		workers = new Worker*[count];
		if(!workers)
		{
			wchar_t msg[512];
			StringCbPrintf(msg, 512, L"Error: Could not allocate memory for worker pointer storage");
			Snowstorm::Error::SignalError(L"Allocation Error", msg);
		}

		// initialise the workers
		for(int i = 0; i < count; i++)
		{
			workers[i] = new Worker(i + 1);
			if(!workers[i])
			{
				wchar_t msg[512];
				StringCbPrintf(msg, 512, L"Error: Could not allocate memory for worker %u storage", i);
				Snowstorm::Error::SignalError(L"Allocation Error", msg);
			}
		}

		// set the worker count
		worker_count = count;

		// finished
		return;
	}
	else
	{
		workers = NULL;
		worker_count = 0;
		return;
	}
}

void Snowstorm::Worker::StopWorkers()
{
	// stop each worker
	for(int i = 0; i < worker_count; i++)
	{
		workers[i]->Stop();
	}

	// finished
	return;
}


/////////////////////////////////////////////////////
// instance functions

Snowstorm::Worker::Worker(int ID)
{
	// save the thread ID and stop state
	this->stop = false;
	this->ID = ID;

	// create thread
	HANDLE h = CreateThread(NULL, NULL, ThreadEntryPoint, static_cast<LPVOID>(this), NULL, NULL);

	// save params
	this->handle = h;

	// finished
	return;
}

void Snowstorm::Worker::Stop()
{
	// set this to stop
	this->stop = true;

	// finished
	return;
}

void Snowstorm::Worker::Main()
{
	// save a local copy of the thread's ID
	int TID = this->ID;

	// main loop
	while(1)
	{
		// check if there are any jobs available
		Snowstorm::Dispatch::WorkerDispatchTask(TID);

		// check if I need to stop
		if(this->stop)
		{
			break;
		}
	}

	// finished
	return;
}